﻿/* ----------------------------------------------------------------------------
 * Copyright (c) Philip Stears 
 *
 * This source code is subject to terms and conditions of the Microsoft Public 
 * License (Ms-PL).
 * 
 * By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 * 
 * To request a copy of the Microsoft Public License, send a request by email
 * to license@connectbasic.net.
 *
 * This notice must not be removed from this software.
 * ---------------------------------------------------------------------------- */


namespace ConnectBasic.Execution.Binding
{
    using System;
    using Microsoft.Linq.Expressions;
    using Microsoft.Scripting;

    internal class BasicGetIndexBinder : GetIndexBinder
    {
        public BasicGetIndexBinder(CallInfo info)
            : base(info)
        {

        }

        public override DynamicMetaObject FallbackGetIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject errorSuggestion)
        {
            DynamicMetaObject result;

            // COM object?
            if (ComBinder.TryBindGetIndex(this, target, indexes, out result))
            {
                return result;
            }

            // CLR array type
            if (target.RuntimeType.IsArray && target.RuntimeType.GetArrayRank() == indexes.Length)
            {
                var isValid = true;
                var indexExpressions = new Expression[indexes.Length];
                var restrictions = BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value);

                for (int i = 0; i < indexes.Length; i++)
                {
                    var expression = indexes[i].Expression;

                    if (indexes[i].RuntimeType == typeof(int))
                    {
                        indexExpressions[i] = expression;
                        restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction(expression, typeof(int)));
                    }
                    else if (indexes[i].RuntimeType == typeof(short))
                    {
                        indexExpressions[i] = Expression.Convert(expression, typeof(int));
                        restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction(expression, typeof(short)));
                    }
                    else
                    {
                        isValid = false;
                        break;
                    }
                }

                if (isValid)
                {
                    return new DynamicMetaObject(
                        Expression.ArrayIndex(target.Expression, indexExpressions),
                        restrictions);
                }
            }

            // Return an exception
            return errorSuggestion ?? DynamicMetaObject.CreateThrow(target, indexes, typeof(NotImplementedException), (object[])null);
        }
    }
}
